package cn.yili12.server.websocket;

import cn.yili12.server.config.SystemProperties;
import cn.yili12.server.info.vo.InfoMessage;
import cn.yili12.server.info.vo.InfoMessageType;
import cn.yili12.server.mq.QueueProducer;
import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class NioWebSocketChannelPool {

    private final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    private final Map<String, Channel> map = new ConcurrentHashMap<>(); //用户-通道
    private final Map<String, String> orgUserMap = new ConcurrentHashMap<>(); //用户-组织

    @Autowired
    private QueueProducer producer;
    @Autowired
    private SystemProperties systemProperties;

    /**
     * 新增一个客户端通道
     *
     * @param channel
     */
    public synchronized void addChannel(Channel channel) {
        channels.add(channel);
    }

    /**
     * 移除一个客户端连接通道
     *
     * @param channel
     */
    public synchronized void removeChannel(Channel channel) {
        channels.remove(channel);
        for (String key : map.keySet()) {
            if (map.get(key) == channel) {
                map.remove(key);
                orgUserMap.remove(key);
                sendOffline(key);
                break;
            }
        }
    }

    /**
     * 获取所有在线用户列表
     *
     * @return
     */
    public List<String> getOnlineList() {
        Set<String> strings = map.keySet();
        return new ArrayList<>(strings);
    }

    private void sendOffline(String name) {
        InfoMessage infoMessage = new InfoMessage();
        infoMessage.setTo("");
        infoMessage.setFrom(name);
        infoMessage.setData(name);
        infoMessage.setType(InfoMessageType.Offline);
        infoMessage.setNo(String.valueOf(System.currentTimeMillis()));
        //告诉所有客户端
        producer.send(systemProperties.getInfoQueue(), JSON.toJSONString(infoMessage));
        //告诉业务系统
        producer.send(systemProperties.getDbQueue(), JSON.toJSONString(infoMessage));
    }

    /**
     * 增加一个真实 用户
     *
     * @param name
     * @param channel
     */
    public void add(String org, String name, Channel channel) {
        orgUserMap.put(name, org);
        map.put(name, channel);
    }

    /**
     * 发送给指定用户
     *
     * @param name
     * @param msg
     */
    public boolean sendTo(String name, String msg) {
        try {
            Channel channel = map.get(name);
            if (channel != null) {
                channel.writeAndFlush(new TextWebSocketFrame(msg));
                return true;
            } else {
                log.warn("用户{}不在线", name);
                return false;
            }
        } catch (Exception e) {
            log.error("给客户端发送websocket信息报错", e);
            return false;
        }
    }

    /**
     * 广播给每一个真是用户
     *
     * @param msg
     */
    public void broadcast(String name, String msg) {
        String orgId = orgUserMap.get(name);
        Set<String> list = new HashSet<>();
        //找到所有同一组织得用户
        for (String key : orgUserMap.keySet()) {
            if (orgUserMap.get(key).equals(orgId) && !key.equals(name)) {
                list.add(key);
            }
        }
        //发送给这些组织信息
        for (String key : list) {
            Channel channel = map.get(key);
            channel.writeAndFlush(new TextWebSocketFrame(msg));
        }
    }
}